package com.example.bookstore.api

import com.example.bookstore.exception.BaseException
import com.example.bookstore.exception.IdentityNotExistException
import com.example.bookstore.exception.LogException
import com.example.bookstore.response.ErrorResponse
import io.jsonwebtoken.JwtException
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.validation.BindException
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RestControllerAdvice
import java.util.*
import javax.servlet.http.HttpServletRequest
import javax.validation.ConstraintViolationException

/**
 * Created by IntelliJ IDEA.
 * User: lvshe
 * Date: 2019/8/14
 * Time: 20:53
 */
@RestControllerAdvice
class GlobalExceptionHandler {

    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java)
    }

    @ResponseBody
    @ExceptionHandler(IdentityNotExistException::class)
    fun identityNotExistExceptionHandle(e: IdentityNotExistException, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        return ResponseEntity(ErrorResponse(e.localizedMessage, request), e.status)
    }

    @ResponseBody
    @ExceptionHandler(LogException::class)
    fun logExceptionHandle(e: LogException, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        val timestamp = Calendar.getInstance().timeInMillis
        logger.warn("${e.message} $timestamp")
        return ResponseEntity(ErrorResponse("服务器内部错误，请联系管理员, timestamp: $timestamp", request), e.status)
    }

    @ResponseBody
    @ExceptionHandler(JwtException::class)
    fun tokenExceptionHandle(e: JwtException, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        return ResponseEntity(ErrorResponse(e.localizedMessage, request), HttpStatus.FORBIDDEN)
    }

    @ResponseBody
    @ExceptionHandler(BindException::class)
    fun bindException(e: BindException, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        val message = e.bindingResult.fieldErrors.mapNotNull { "${it.field} ${it.defaultMessage}" }.joinToString(", ")
        return ResponseEntity(ErrorResponse(message, request), HttpStatus.BAD_REQUEST)
    }
    @ResponseBody
    @ExceptionHandler(ConstraintViolationException::class)
    fun bindException(e: ConstraintViolationException, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        val message =  e.constraintViolations.map { "${it.propertyPath}${it.message}" }.joinToString(", ")
        return ResponseEntity(ErrorResponse(message, request), HttpStatus.BAD_REQUEST)
    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException::class)
    fun methodArgumentNotValidExceptionException(e: MethodArgumentNotValidException, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        val message = e.bindingResult.fieldErrors.mapNotNull { "${it.field} ${it.defaultMessage}" }.joinToString(", ")
        return ResponseEntity(ErrorResponse(message, request), HttpStatus.BAD_REQUEST)
    }

    @ResponseBody
    @ExceptionHandler(BaseException::class)
    fun baseExceptionHandle(e: BaseException, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
        return ResponseEntity(ErrorResponse(e.localizedMessage, request), e.status)
    }

//
//    @ResponseBody
//    @ExceptionHandler(Exception::class)
//    fun exception(e: Exception, request: HttpServletRequest): ResponseEntity<ErrorResponse> {
//        System.err.println(e.javaClass)
//        return ResponseEntity(ErrorResponse(e, request), HttpStatus.BAD_REQUEST)
//    }
}